-module(node).
-behaviour(supervisor).
% OTP interface
-export([start_link/0]).
-export([init/1]).

% Client interface
-export([start/0,start_join/1,stop/0,
         join/1,leave/0,
         put/2,get/1,
         status/0]).

% start and stop functions
start() -> delay(1000),
           {ok,Pid} = start_link(),
           unlink(Pid), % Needed when started from command line?
           {ok,Pid}.

start_join(Args) ->
    case is_atom(Args) of
        true  ->  Node = Args;
        false ->  Node = lists:nth(1,Args)
    end,
    delay(1000),
    {ok,Pid} = start_link(),
    delay(100),
    R2 = join(Node),
    unlink(Pid),
    {ok, {ok,Pid}, R2}.

stop() -> Pid = whereis(?MODULE),
          case Pid of 
            undefined -> {error, not_started};
            _         -> exit(Pid, shutdown),
                         {ok, shutdown}
          end.

% join and leave functions
%
% chorder is responsible for chord connections
% TODO should not be possible to join a chord if we already are 
% connected to another
join(Node) ->
    gen_server:call(chorder, {join, Node}).

leave() -> 
    gen_server:call(chorder, {leave}).

% put and get are synchronous calls, use handle calls
% send request to chorder to redirect to the responsible node
put(Key, Value) ->
    gen_server:call(chorder, {put, Key, Value}).

get(Key) ->
    gen_server:call(chorder, {get, Key}).

% Get node status, for debugging
status() ->
    Nodes  = gen_server:call(chorder, {status}),
    Values = gen_server:call(storager, {status}),
    io:format("Nodes: ~w~nValues: ~p~n",[[X || {_,X}<-Nodes]
                                       , [Y || {_,Y}<-Values]]),
    {ok, status}.
    

% OTP
start_link() ->
    io:format("Starting node\n"),
    supervisor:start_link({local, ?MODULE}, node, []).

init(_Args) ->
    {ok, {{one_for_one, 10, 60},
          [{storager, {storager, start_link, orddict:new()},
            permanent, 5000, worker, [storager]},
          {chorder, {chorder, start_link, ordsets:new()},
            permanent, 5000, worker, [chorder]}]}}.



% Helper functions
delay(Time) ->
    receive
    after Time -> ok
    end.
